package com.cby.operation.login

import android.app.Activity
import android.app.Fragment
import android.text.TextUtils
import com.cby.operation.anti.AntiAddictListener
import com.cby.operation.anti.AntiAddictManager
import com.cby.operation.common.ui.UIStackManager
import com.cby.operation.common.util.CbyLogUtils
import com.cby.operation.common.util.FastClickUtils
import com.cby.operation.common.util.HandlerUtils
import com.cby.operation.common.util.NetworkUtils
import com.cby.operation.initialize.InitManager
import com.cby.operation.login.data.InternalTip
import com.cby.operation.login.data.InternalUser
import com.cby.operation.login.data.LoginApiRepository
import com.cby.operation.login.ui.LoginAuthFragment
import com.cby.operation.login.ui.LoginTipDialogFragment
import com.cby.operation.login.ui.LoginWebDialogFragment
import com.cby.operation.sdk.*
import com.cby.operation.sdk.storage.SDKStorage
import com.cby.operation.sdk.util.HykbAppUtils
import com.cby.operation.sdk.util.UserUtils


/**
 * @description: LoginManager
 *
 * @author ChenBaoyang
 * @date 7/22/21 15:52
 */
class LoginManager : AntiAddictListener {

    /**
     * sdk内部使用的用户信息对象
     */
    private var user: InternalUser? = null

    /**
     * sdk对外使用的用户信息对象
     */
    private var userInfo: UserInfo? = null

    /**
     * 用来缓存最近一次登录的用户ID
     */
    private var lastUserId: String? = null

    /**
     * 登录回调接口
     */
    private var listener: LoginListener? = null

    /**
     * activity上下文（游戏主窗口）
     */
    private var activity: Activity? = null

    /**
     * 提醒或者警告之类的弹窗对象
     */
    private var tipDialog: LoginTipDialogFragment? = null

    private object SingletonHolder {
        /**
         * 返回InitManager对象
         */
        val instance = LoginManager()
    }


    companion object {
        val instance = SingletonHolder.instance
        private const val DAY_UNIT = (24 * 60 * 60).toLong()
    }

    /**
     * 对外调用的登录入口
     *
     * @param activity Activity  上下文
     * @param switchUser Boolean  用来表示是否是切换账号操作
     * @param listener LoginListener  登录回调监听
     */
    fun doLogin(activity: Activity, switchUser: Boolean, listener: LoginListener) {

        this.activity = activity
        this.listener = listener
        if (FastClickUtils.isFastDoubleClick) {
            return
        }

        if (!NetworkUtils.isConnected(activity)) {
            handleFailedCallback(ERR_CODE_NETWORK_ERROR, ERR_MSG_NETWORK_ERROR)
            return
        }

        if (!InitManager.instance.isInitOK()) {
            //未初始化成功，不让调用登录
            handleFailedCallback(ERR_CODE_SDK_NOT_INIT_OK, ERR_MSG_SDK_NOT_INIT_OK)
            return
        }

        if(switchUser) {
            //表示切换账号
            internalLogin(activity)
            return
        }

        if( userInfo != null ) {
            //当前已经登录了，直接返回用户信息
            handleSuccessCallback()
            return
        }

        val fromPaid: Boolean = SDKStorage.getFlag(activity)
        CbyLogUtils.flog("fromPaid$fromPaid")
        //判断是否直接用付费下载的用户信息
        if (fromPaid) {
            val nick: String? = SDKStorage.getUserNick(activity!!.applicationContext)
            val state: String? = SDKStorage.getUserState(activity!!.applicationContext)
            val info = state?.split("\\|".toRegex())?.toTypedArray()
            if (info != null && info.isNotEmpty()) {
                // 创建用户信息实体对象，用户信息验证
                createInternalUser(info[0], nick.toString(), info[1], info[2])
                return
            }
        }

        //检查用户缓存是否在有效期内
        if(checkUserCache()) {
            return
        }

        //触发内部登录（授权或者web登录）
        internalLogin(activity)
    }

    private fun internalLogin(activity: Activity) {
        if (HykbAppUtils.checkHykbSupport(activity)) {
            //满足条件，开启透明层，调用快爆app的登录
            val fm = activity.fragmentManager
            var current: Fragment? = fm.findFragmentByTag(
                TAG_FRAGMENT_LOGIN_AUTH
            )
            if (current == null) {
                current = LoginAuthFragment()
                fm.beginTransaction()
                    .add(current, TAG_FRAGMENT_LOGIN_AUTH)
                    .commitAllowingStateLoss()
            } else {
                (current as LoginAuthFragment).userInfoFromHykbApp
            }
        } else {
            doLoginWeb(activity)
        }
    }

    /**
     * 检查用户缓存数据
     *
     * @return Boolean
     */
    private fun checkUserCache(): Boolean {
        //根据服务端给的有效期确认是否走缓存数据
        val validity = InitManager.instance.initConfig!!.validity
        if (validity > 0) {
            // 获取本地缓存
            val firstTime: Long = SDKStorage.getFirstTime(activity!!)
            // 判断下是否有缓存，如果没有照样走手动登录
            val expireTime: Long = firstTime + Companion.DAY_UNIT * validity
            // 判断有缓存数据，切在有效期内
            val currentTime = System.currentTimeMillis()
            if (firstTime > 0 && expireTime * 1000 > currentTime && firstTime * 1000 < currentTime) {
                val nick: String? = SDKStorage.getUserNick(activity!!.applicationContext)
                val state: String? = SDKStorage.getUserState(activity!!.applicationContext)
                val info = state?.split("\\|".toRegex())?.toTypedArray()
                if (info != null && info.isNotEmpty()) {
                    // 创建用户信息实体对象，用户信息验证
                    createInternalUser(info[0], nick.toString(), info[1], info[2])
                    return true
                }
            }
        }
        return false
    }

    /**
     * 调用web页面的登录
     *
     * @param activity Activity
     */
    @Synchronized
    fun doLoginWeb(activity: Activity) {
        if (UIStackManager.instance!!.hasFragment(TAG_FRAGMENT_LOGIN_WEB)) {
            return
        }
        val loginWeb = LoginWebDialogFragment()
        loginWeb.show(activity.fragmentManager, TAG_FRAGMENT_LOGIN_WEB)
    }


    /**
     * 生成sdk内部使用的用户信息实体
     *
     * @param userId String
     * @param nick String
     * @param loginType String
     * @param token String
     */
    fun createInternalUser(userId: String, nick: String, loginType: String, token: String) {
        user = InternalUser(userId, nick, loginType, token)

        LoginApiRepository.authCheck(
            SdkConfiguration.gameId,
            user,
            object : LoginApiRepository.OnLoginApiCallback {
                override fun onUserCheckSucceed() {
                    //缓存用户信息
                    cacheUser()
                    // 对外的用户信息转化
                    userInfo = UserInfo(userId, nick, user!!.accessToken)
                    // 校验成功之后回调给游戏方
                    handleSuccessCallback()

                    //账号变化了，先做防沉迷关闭操作
                    if (!TextUtils.isEmpty(lastUserId) && !TextUtils.equals(lastUserId, userId)) {
                        //关闭防沉迷
                        AntiAddictManager.instance.stopAnti()
                    }

                    //开启防沉迷检测
                    activity?.let {
                        AntiAddictManager.instance.startAnti(
                            it,
                            userId,
                            nick,
                            loginType,
                            token,
                            this@LoginManager
                        )
                    }

                    //缓存上次的账号
                    lastUserId = userId

                    //关闭相关弹窗
                    UIStackManager.instance!!.finishFragment(TAG_FRAGMENT_LOGIN_WEB)

                }

                override fun onUserCheckFailed(code: Int, msg: String?) {
                    // 用户校验失败
                    handleFailedCallback(code, msg)
                    user = null
                    userInfo = null
                    CbyLogUtils.flog("code = ${code}, msg = $msg")
                }

                override fun onUserBanned(code: Int, tip: InternalTip) {
                    logout(activity)
                    userBanned(activity!!, tip)
                }

            })
    }


    /**
     * 用户信息缓存
     */
    fun cacheUser() {
        SDKStorage.clearCache(activity!!.applicationContext)
        SDKStorage.saveUserNick(activity!!.applicationContext, user!!.nick)
        SDKStorage.saveUserState(activity!!.applicationContext, UserUtils.getState(user))
        SDKStorage.saveFirstTime(activity!!.applicationContext, System.currentTimeMillis() / 1000)
        SdkConfiguration.userId = user!!.userId.toString()
    }


    /**
     * 用户本封号或者强登录
     *
     * @param tip InternalTip?
     */
    fun userBanned(activity: Activity, tip: InternalTip?) {
        if (UIStackManager.instance!!.hasFragment(TAG_FRAGMENT_TIP_BANNED)) {
            tipDialog!!.update(tip!!)
        } else {
            tipDialog = LoginTipDialogFragment.show(activity, tip!!)
        }
    }

    /**
     * 注销账号
     *
     * @param activity Activity?
     */
    fun logout(activity: Activity?) {
        //注销账号，清除用户信息, 结束防沉迷
        if (user != null) {
            // 结束防沉迷
            AntiAddictManager.instance.stopAnti()
            user = null
            userInfo = null
            SDKStorage.clearCache(activity!!)
        }

    }

    /**
     * 登录失败的相关回调
     *
     * @param code Int
     * @param msg String
     */
    fun handleFailedCallback(code: Int, msg: String?) {
        HandlerUtils.runOnMainThread() {
            listener?.onLoginFailed(code, msg)
        }
    }

    /**
     * 登录成功回调给游戏方
     */
    fun handleSuccessCallback() {
        HandlerUtils.runOnMainThread() {
            listener?.onLoginSuccess(userInfo!!)
        }
    }

    /**
     * 内部使用的用户信息
     *
     * @return InternalUser?
     */
    fun getUser() : InternalUser?{
        return user
    }

    /**
     * 对外部使用的用户信息
     *
     * @return InternalUser?
     */
    fun getUserInfo() : UserInfo?{
        return userInfo
    }

    fun isLogin() : Boolean{
        return user != null
    }

    /**
     * 信息重制
     */
    fun reset() {
        user = null
        userInfo = null
        lastUserId = null
        SdkConfiguration.userId = "0"
    }

    override fun onEventBack(code: Int, message: String) {
        CbyLogUtils.flog("code = $code --- message = $message")
        handleFailedCallback(code, message)
    }


}